package main;
import java.util.List;
import java.util.Arrays;

abstract public class Operation implements Expression {
	private List<Expression> operands;
	protected String symbol;
	public static Notation notation = Notation.INFIX;

	public Operation(String s, Expression... ops) {
		symbol = s;
		operands = Arrays.asList(ops);
	}

	public Operation(int l, int r, String s) {
		operands = Arrays.asList((Expression)new MyNumber(l), (Expression)new MyNumber(r));
		symbol = s;
	}

	public final int compute() {
		int acc = operands.get(0).compute();
		for (int i=1; i<operands.size(); i++)
			acc = op(acc, operands.get(i).compute());
		return acc;
	}

	public final void print() {
		System.out.println(toString());
	}

	public final String toString() {
		StringBuilder sb = new StringBuilder();
		//Maybe PREFIX
		if (notation == Notation.PREFIX) {
			sb.append(symbol);
			sb.append(" ");
		}
		//Operands (and symbol if INFIX)
		String prefix = ""; //trick from SO
		for (Expression x: operands) {
			sb.append(prefix);
			if (notation == Notation.INFIX)
				prefix = " "+symbol+" ";
			else
				prefix = " ";
			if (x instanceof MyNumber)
				sb.append(x.toString());
			else {
				sb.append("(");
				sb.append(x.toString());
				sb.append(")");
			}
		}
		//Maybe POSTFIX
		if (notation == Notation.POSTFIX) {
			sb.append(" ");
			sb.append(symbol);
		}
		//Done
		return sb.toString();
	}

	public int countOps() {
		int acc = 1;
		for (Expression x: operands)
			acc += x.countOps();
		return acc;
	}

	public int countDepth() {
		int best=0, cur;
		for (Expression x: operands)
			if ((cur=x.countDepth()) > best)
				best = cur;
		return 1+best;
	}

	public int countNbs() {
		int acc = 0;
		for (Expression x: operands)
			acc += x.countNbs();
		return acc;
	}

	abstract protected int op(int l, int r); //the operation itself is specified in the subclasses
}


